#include "miiPin.h"

#include "..\..\include\imp_typedefine.h"
#include "..\..\include\imp_io_wrapper.h"

static CMiiShowPinIn *g_Pin = 0;

void GetPictureFromPin(char ** pBuffer, int* width, int* height, int* bitCount, int* color)
{
	if(g_Pin)
		g_Pin->GetPicture(pBuffer, width, height, bitCount, color);
}

CMiiShowPinIn::CMiiShowPinIn(CBaseFilter *pFilter, HRESULT *phr,int width,int hight) : CBaseInputPin(NAME("CVideoPinIn"), pFilter, this, phr, L"MiiShow_Vedio_input")
, m_bCopy(false)
{
	m_nResolutionWidth = width;
	m_nResolutionHeight = hight;
	g_Pin = this;
	ZeroMemory(&m_tType, sizeof(m_tType));
	m_pBuffer[0] = new char[320*240*3];
	m_pBuffer[1] = new char[320*240*3];
	m_nBufIndex = 0;
	m_nMaxCount = 0;
	mOutWidth  = 176;
	mOutHeight = 144;
}

CMiiShowPinIn::~CMiiShowPinIn()
{
	delete []m_pBuffer[0];
	delete []m_pBuffer[1];
}

HRESULT CMiiShowPinIn::CompleteConnect(IPin *pReceivePin)
{
	return S_OK;
}

HRESULT CMiiShowPinIn::SetMediaType(const CMediaType *p)
{
	if(NULL != p->pbFormat)
	{
		memcpy(&m_vInfo, p->pbFormat, sizeof(VIDEOINFOHEADER));
		mOutWidth = m_vInfo.bmiHeader.biWidth;
		mOutHeight = m_vInfo.bmiHeader.biHeight;
		return S_OK;
	}
	return S_FALSE;
}

HRESULT CMiiShowPinIn::CheckConnect(IPin *)
{
	return S_OK;
}

HRESULT CMiiShowPinIn::CheckMediaType(const CMediaType *pmt)
{
	WCHAR strGuid[39];
	StringFromGUID2(pmt->subtype, strGuid, 39);
	wprintf(L"MediaType GUID = %s ", strGuid);
	VIDEOINFOHEADER * pvih;
	/*if (pmt->subtype != MEDIASUBTYPE_RGB565 && pmt->subtype != MEDIASUBTYPE_YV12) 
		return FALSE;*/
	pvih = (VIDEOINFOHEADER*)pmt->pbFormat;
	wprintf(L"biWidth = %d ", pvih->bmiHeader.biWidth);
	wprintf(L"biHeight = %d\n", pvih->bmiHeader.biHeight);
	 if (pmt->subtype == MEDIASUBTYPE_YV12)
	 {
		m_mediaType = YV12;
	 }
	 else if(pmt->subtype == MEDIASUBTYPE_RGB565)
	 {
	    m_mediaType = RGB565;
	 }
	 else
	 {
		return S_FALSE;
	 }
	if(pmt->pbFormat){
		pvih = (VIDEOINFOHEADER*)pmt->pbFormat;
		if(m_mediaType == RGB565 && pvih->bmiHeader.biBitCount != 16)
			return S_FALSE;
		else if (m_mediaType == YV12 && pvih->bmiHeader.biBitCount != 12)
			return S_FALSE;
		/*if (160 > pvih->bmiHeader.biWidth || 128 > pvih->bmiHeader.biHeight)
		{
			return S_FALSE;
		}*/
		if (m_nResolutionWidth != pvih->bmiHeader.biWidth || m_nResolutionHeight != pvih->bmiHeader.biHeight)
		{
			m_nMaxCount++;
			if (m_nMaxCount < 9)
			{
				return S_FALSE;
			}
		}
	}
	else{
		return S_FALSE;
	}
	return S_OK;
}

HRESULT CMiiShowPinIn::GetMediaType(int iPosition, CMediaType *pMediaType)
{
	if (iPosition < 0)
	{
		return E_INVALIDARG;
	}

	if (!m_tType.IsValid())
	{
		return VFW_S_NO_MORE_ITEMS;
	}
	
	if (iPosition > 0)
	{
		return VFW_S_NO_MORE_ITEMS;
	}

	if (pMediaType)
	{
		CopyMediaType(pMediaType, &m_tType);
	}

	return S_OK;
}

CMediaType *CMiiShowPinIn::MediaType()
{
	return &m_mt;
}

extern void miidx_input_video(Int8 *pBuffer, UInt32 pts, Int32 width, Int32 height, Int32 mediaType);

STDMETHODIMP CMiiShowPinIn::Receive(IMediaSample *pSample)
{
	HRESULT hr;
	char *pBuffer = NULL;
	int nLength = 0;
	int width, height;
	LONGLONG tstart, tend;
	
	CheckPointer(pSample,E_POINTER);

	AM_MEDIA_TYPE tempMt = {0};
	AM_MEDIA_TYPE *pmt = NULL;
    pSample->GetMediaType(&pmt);
	if(S_OK == pSample->GetMediaType(&pmt))
	{
		if(pmt->pbFormat){
			 memcpy(&tempMt, pmt, sizeof(AM_MEDIA_TYPE));
		}
	}
    DeleteMediaType(&tempMt);

	hr = pSample->GetPointer((BYTE **)&pBuffer);
	nLength = pSample->GetActualDataLength();

	/*if(m_bCopy){
		memcpy(m_pBuffer[m_nBufIndex], pBuffer, min(nLength, 320*240*3));
		m_nBufIndex ^= 1;
		m_bCopy = false;
	}*/

	hr = pSample->GetTime(&tstart, &tend);

	if(hr==S_OK)
	{
		mTimeStamp = tstart/10000;
		miidx_input_video(pBuffer, mTimeStamp, mOutWidth, mOutHeight, m_mediaType);
	}

	return S_OK;
}

// get picture from the pin
void CMiiShowPinIn::GetPicture(char ** pBuffer, int* width, int* height, int* bitCount, int* color)
{
	if(m_bCopy)
		*pBuffer = 0;
	else
		*pBuffer = m_pBuffer[m_nBufIndex];
	*width	= m_vInfo.bmiHeader.biWidth;
	*height	= m_vInfo.bmiHeader.biHeight;
	*bitCount = m_vInfo.bmiHeader.biBitCount;
	*color = 4;
	m_bCopy = true;
}
//template<class T> inline static T ourmax( const T & a, const T & b )
//{
//	return a > b ? a : b;
//}
STDMETHODIMP_(ULONG) CMiiShowPinIn::NonDelegatingAddRef()
{
	ASSERT(InterlockedIncrement(&m_cRef) > 0);
	return m_pFilter->AddRef();
}

STDMETHODIMP_(ULONG) CMiiShowPinIn::NonDelegatingRelease()
{
	ASSERT(InterlockedDecrement(&m_cRef) >= 0);
	return m_pFilter->Release();
}